// 信号量的用法
#include <iostream>
#include <pthread.h>
#include <stdio.h>

using namespace std;

#define BOUNDARY 5

int tasks = 10;

pthread_mutex_t tasks_mutex; // 因为两个线程要修改一个全局变量，需要互斥量
pthread_cond_t tasks_cond; // 因为两个线程之间有条件关系：当tasks>5时，hello2处理它，处理一次减少1；反之hello1处理，直到tasks减为零；

void * say_hello2(void* args) {
	pthread_t pid = pthread_self(); // 打印当前线程id便于跟踪
	cout << "["<< pid << "] hello in thread " << *((int *)args) << endl;

	bool is_signaled = false;

	for( ; ; ) {
		pthread_mutex_lock(&tasks_mutex);
		// >5才修改
		if (tasks > BOUNDARY) {
			cout << "["<< pid << "] take tasks: " << tasks << " in pthread " <<  *((int *)args) << endl;
			--tasks;
		}
		else if (!is_signaled) {
			cout << "["<< pid << "] pthread_cond_signal in thread " << *((int *)args) << endl;
			pthread_cond_signal(&tasks_cond); // 表明已经不是>5了 告诉hello1进程去处理：发送信号
			is_signaled = true;
		}
		pthread_mutex_unlock(&tasks_mutex); // 操作完 解锁

		if (tasks == 0) break; //必须等待tasks全部减为零即hello1完成操作，才跳出循环结束这个进程 
	}
}

//<=5处理函数
void* say_hello1(void* args) {
	pthread_t pid = pthread_self();
	cout << "["<< pid << "] hello in thread " << *((int *)args) << endl;
	for ( ; ; ) {
		pthread_mutex_lock(&tasks_mutex);
		//如果>5说明需要hello2处理，那么该线程就需要等待 
		if (tasks > BOUNDARY) {
			cout << "["<< pid << "] pthread_cond_wait in thread " << *((int *)args) << endl;
			pthread_cond_wait(&tasks_cond, &tasks_mutex); //等待信号量生效，当hello2发出信号，这里就跳出wait，执行后续
		} else {
			cout << "["<< pid << "] take tasks: " << tasks << " in pthread " <<  *((int *)args) << endl;
			--tasks; // < 5就--
		}
		pthread_mutex_unlock(&tasks_mutex);
	}
}

int main() {
	pthread_attr_t attr;
	pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

	pthread_mutex_init (&tasks_mutex, NULL); // 对锁的初始化
	pthread_cond_init (&tasks_cond, NULL); // 对信号量的初始化
	pthread_t tid1, tid2;//用于保存两个线程的id号

	int index1 = 1;
	int ret = pthread_create(&tid1, &attr, say_hello1, (void *) &(index1));
	if (ret != 0) {
			cout << "pthread_create error: error_code=" << ret << endl;
		}
	int index2 = 2;
	ret = pthread_create(&tid2, &attr, say_hello1, (void *) &(index2));
	if (ret != 0) {
			cout << "pthread_create error: error_code=" << ret << endl;
		}

	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);
	pthread_attr_destroy(&attr);
	pthread_mutex_destroy(&tasks_mutex);
	pthread_cond_destroy(&tasks_cond);
}